#pragma oce
#include<iostream>
#include<memory>
#include<sys/epoll.h>
#include"EpollMethod.hpp"
#include"Socket.hpp"
#include"log.hpp"
#include"nocopy.hpp"
extern Log lg;
//IO多路转接之Epoll模型
static const uint16_t defaultport=8811;
uint32_t EVENT_IN=(EPOLLIN);
uint32_t EVENT_OUT=(EPOLLOUT);

class EpollServer:public nocopy
{
    static const int nums=64;
    public:
    EpollServer(const uint16_t&port=defaultport)
    :port_(port),listensock_ptr(new Sock()),epoll_ptr(new Epoll())//初始化列表是根据成员你变量声明顺序初始化的，跟你这里写的顺序毫无关系！！！
    {
      //  epoll_ptr->EpollUpdata(EPOLL_CTL_ADD,listensock_ptr->Fd(),EVENT_IN);
        //千万不能再这里添加listensockfd ，因为这个时候listenfd还没赋值，要调用Socket()之后listenfd才存在
    }
    bool Init()
    {
        //服务器初始化
        listensock_ptr->Socket();
        listensock_ptr->Bind(port_);
        listensock_ptr->Listen();
        lg(INFO,"Server init success!!!,listenfd is: %d",listensock_ptr->Fd());
        return true;
    }
    void Accepter()
    {
      std::string clientip;
      uint16_t clientport;
      int sockfd=listensock_ptr->Accept(&clientport,&clientip);
      if(sockfd<0)return;
      lg(DEBUG,"Accept success!! sockfd is:%d, %s:%d",sockfd,clientip.c_str(),clientport);
      epoll_ptr->EpollUpdata(EPOLL_CTL_ADD,sockfd,EVENT_IN);//更新到epoll里，让epoll去等
    }
    void Recver(int fd)
    {
      char buffer[1024];
     ssize_t n= read(fd,buffer,sizeof(buffer)-1);
     if(n>0)
     {
      buffer[n]=0;
      std::cout<<"client say@ "<<buffer<<std::endl;
      std::string echo_str="Sever say@ ";
      echo_str+=buffer;
      write(fd,echo_str.c_str(),echo_str.size());
      
     }
     else if(n==0)
     {
      //取消关心且关掉文件描述符
      lg(INFO,"Read file end!!");
      epoll_ptr->EpollUpdata(EPOLL_CTL_DEL,fd,0);
      close(fd);
     }
     else
     {
      lg(ERROR,"Read error!!");
      epoll_ptr->EpollUpdata(EPOLL_CTL_DEL,fd,0);
      close(fd);

     }
    }
    void Dispatcher(struct epoll_event revs[],int n)
    {
      for(int i=0;i<n;i++)
      {
        int fd=revs[i].data.fd;
        uint32_t events=revs[i].events;
        if(events&EVENT_IN)
        {
          if(fd==listensock_ptr->Fd())
          {
            //处理连接fd
            Accepter();
          }
          else
          {
            //其他fd
            Recver(fd);
          }
        }
        else if(events&EVENT_OUT)
        {

        }
        else{

        }
      }
    }
    void Start()
    {
        //服务器运行
      epoll_ptr->EpollUpdata(EPOLL_CTL_ADD,listensock_ptr->Fd(),EVENT_IN);

        struct epoll_event revs[nums];
        for(;;)
        {
          int n=  epoll_ptr->EpollWait(revs,nums);
          if(n>0)
          {
                std::cout<<"new event!!"<<std::endl;
                Dispatcher(revs,n);
          }
          else if(n==0)
          {
            lg(INFO,"Wait time out!!");
          }
          else
          {
            lg(WARNING,"Wait error!!");
          }
        }
    }
    ~EpollServer()
    {

    }
    private:
    uint16_t port_;
    std::shared_ptr<Sock> listensock_ptr;
    std::shared_ptr<Epoll> epoll_ptr;
};